from pyim import packet
from pyim.io import Client
from . import logger
from .packet import Packet

logger = logger.get_logger(__package__)


class ClientCallback:
    def on_connect(self):
        raise NotImplementedError

    def on_disconnect(self):
        raise NotImplementedError

    def on_auth(self, user, properties):
        raise NotImplementedError

    def on_presence(self, user, status):
        raise NotImplementedError

    def on_message(self, msg):
        raise NotImplementedError

    def on_list(self, users):
        raise NotImplementedError

    def on_error(self, cmd, errcode, errmsg):
        raise NotImplementedError


class ImClient(Client):
    def __init__(self,
                 address):
        Client.__init__(self, address)
        self.session_id = None

    @property
    def callback(self):
        return self._callback

    @callback.setter
    def callback(self, cb):
        assert isinstance(cb, ClientCallback)
        self._callback = cb

    def __getitem__(self, item):
        if not hasattr(self, "_config"):
            return None
        else:
            return getattr(self, "_config")[item]

    def send_data(self, sock, data):
        from .server import ImServer
        logger.info("Sent: {}".format(data))
        return ImServer.send(sock, data)

    def recv_data(self, sock):
        from .server import ImServer
        return ImServer.recv(sock)

    def _send_packet(self, packet):
        assert isinstance(packet, Packet)
        bs = packet.to_bytes("json")
        return self.send_in_queue(self.sock, bs)

    def login(self, username, password):
        setattr(self, "username", username)
        setattr(self, "password", password)

        p = Packet(command="login",
                   sender=username,
                   password=password)
        self._send_packet(p)

    def list(self):
        self._send_packet(Packet(command="list"))

    def config(self):
        self._send_packet(Packet(command="config"))

    def message(self, receiver, message):
        p = Packet(command="message",
                   receiver=receiver,
                   message=message,
                   msg_type=1)
        self._send_packet(p)

    def mark(self, msg_id):
        p = Packet(command="mark",
                   message_id=msg_id)
        self._send_packet(p)

    def on_connect(self, sock, server):
        super().on_connect(sock, server)

        if hasattr(self, "username") and hasattr(self, "password"):
            self.login(self.username, self.password)
        if self._callback:
            self._callback.on_connect()

    def on_received(self, sock, data):
        p = packet.Packet(data, serializer_name="json")
        command = p["command"]
        if 'errcode' in p and p['errcode'] != 0:
            self._callback.on_error(p["command"], p["errcode"], p["errmsg"])
        elif command == "list":
            self._callback.on_list(p["user_list"])
        elif command == "login":
            self._callback.on_auth(p["receiver"], p["properties"])
        elif command == "message":
            self._callback.on_message(p)
        elif command == "config":
            for k in p["arguments"]:
                setattr(self, k, p["arguments"][k])
        elif command == "presence":
            self._callback.on_presence(p["username"], p["status"])

    def on_sent(self, sock, data, sz_send):
        super().on_sent(sock, data, sz_send)

    def on_disconnect(self, client):
        if self._callback:
            self._callback.on_disconnect()
        super().on_disconnect(client)
